package cn.dcw.pethome.user.service.impl;

import cn.dcw.pethome.basic.exception.MyException;
import cn.dcw.pethome.basic.util.AjaxResult;
import cn.dcw.pethome.basic.util.HttpClientUtils;
import cn.dcw.pethome.basic.util.MD5Utils;
import cn.dcw.pethome.basic.util.StrUtils;
import cn.dcw.pethome.user.constant.LoginConstant;
import cn.dcw.pethome.user.domain.User;
import cn.dcw.pethome.user.domain.WxUser;
import cn.dcw.pethome.user.dto.LoginDto;
import cn.dcw.pethome.user.domain.LoginInfo;
import cn.dcw.pethome.user.mapper.LoginInfoMapper;
import cn.dcw.pethome.user.mapper.UserMapper;
import cn.dcw.pethome.user.mapper.WxUserMapper;
import cn.dcw.pethome.user.service.ILoginService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.thymeleaf.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private LoginInfoMapper loginInfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private WxUserMapper wxUserMapper;
    @Autowired
    private UserMapper userMapper;


    //普通用户登入
    @Override
    public AjaxResult otLogin(LoginDto loginDto) {
        //1.非空判断
        if(StringUtils.isEmpty(loginDto.getUsername())||StringUtils.isEmpty(loginDto.getPassword())){
            throw new MyException("用户名或密码不能为空***");
        }
        //2.通过用户名和type（区分用户和员工）查询用户
        LoginInfo loginInfo = loginInfoMapper.findByUserNameType(loginDto);
        //3.判断这个对象是否存在
        if(loginInfo==null){
            throw new MyException("用户名或密码错误***");
        }
        //4.判断密码
        String salt = loginInfo.getSalt();//当前对象，所对应的颜值
        String password = MD5Utils.encrypByMd5(loginDto.getPassword() + salt);
        //将客户输入的密码，加密后和数据库的密码进行比较
        if(!password.equals(loginInfo.getPassword())){
            throw new MyException("密码错误***");
        }
        //5.记录对象loginInfo到redis中key值为token
        String token = UUID.randomUUID().toString();
        //设置对象在redis中保存的时间为30分钟有效
        redisTemplate.opsForValue().set(token, loginInfo, 30, TimeUnit.MINUTES);
        //6.如果登入成功需要返回 token和 对象 loginInfo
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        //对象传递到前端前，将隐蔽数据清空
        loginInfo.setSalt("");
        loginInfo.setPassword("");
        map.put("loginInfo", loginInfo);
        return new AjaxResult(true,"登入成功",map);
    }

    /**
     * 前端门户网站，微信登入
     * @param map
     * @return
     */
    @Override
    public AjaxResult wechatLogin(Map<String,String> map) {
        //获取code
        String code = map.get("code");
        //1.非空判断
        if(StringUtils.isEmpty(code)){
            throw new MyException("系统异常***");
        }
        //2.通过code  APPID SECRET获取token令牌  replace替换
        String url=LoginConstant.GET_TOKEN_URL.replace("APPID", LoginConstant.APPID)
                .replace("SECRET", LoginConstant.SECRET)
                .replace("CODE", code);
        String obj = HttpClientUtils.httpGet(url);
        //将json字符串转换为对象
        JSONObject jsonObject = JSONObject.parseObject(obj);
        //获取access_token+openId
        String access_token = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");
        //判断openId是已经存在（查询t_wxUser），
        WxUser wxUser = wxUserMapper.loadByOpenId(openid);
        //第一次微信扫码需要
        String param="?token="+access_token+"&openid="+openid;
        if(wxUser!=null && wxUser.getUser_id()!=null){//如果已经有了并且userid不为空,说明之前扫描过，直接免密登录
            //记录对象loginInfo到redis中key值为token
            String token = UUID.randomUUID().toString();
            //通过微信对象字段user_id查询对象记录
            LoginInfo loginInfo = loginInfoMapper.findByUserId(wxUser.getUser_id());
            //设置对象在redis中保存的时间为30分钟有效
            redisTemplate.opsForValue().set(token, loginInfo, 30, TimeUnit.MINUTES);
            //创建一个map储存数据，返回数据给前端
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("token", token);
            //对象传递到前端前，将隐蔽数据清空
            loginInfo.setSalt("");
            loginInfo.setPassword("");
            resultMap.put("loginInfo", loginInfo);
            return new AjaxResult(true, "登入成功", resultMap);
        }else {
            //如果为空，需要让用户绑定个人用户信息,返回token+openId 前端帮我们跳转到绑定页面
            return new AjaxResult(false, "请填写用户信息", param);
        }

    }

    /**
     * 微信绑定
     * @param map
     * @return
     */
    @Override
    public Map<String, Object> wechatBinder(Map<String, String> map) {

        //获取appendId  和token
        String accessToken = map.get("accessToken");
        String openId = map.get("openId");
        String phone = map.get("phone");
        String verifyCode = map.get("verifyCode");
        //非空判断
        if(StringUtils.isEmpty(phone)){
            throw new MyException("电话号码不能为空***");
        }
        if(StringUtils.isEmpty(verifyCode)){
            throw new MyException("验证码不能为空***");
        }
        if(!StringUtils.isEmpty(accessToken)){

            //判断当前电话是否之前注册过用户，如果有，直接关联对象
            User oldUser = userMapper.findOneByPhone(map.get("phone"));
            User user = null;
            LoginInfo loginInfo = null;
            if(oldUser!=null){//注册过
                user=oldUser;
                loginInfo = loginInfoMapper.findByUserId(user.getId());
            }else {
                //生成用户user,logininfo  wxuser  这三张表
                user = initUser(phone);
                loginInfo = initLoginInfo(user);
                loginInfoMapper.add(loginInfo);
                user.setLogininfo_id(loginInfo.getId());
                userMapper.add(user);
            }
            //通过appendId  和token  获取用户微信信息
            String getUserUrl = LoginConstant.GET_USER_URL
                    .replace("ACCESS_TOKEN", accessToken)
                    .replace("OPENID", openId);
            //调用工具类,生成用户对象
            String userObj = HttpClientUtils.httpGet(getUserUrl);
            //调用工具类将字符串对象转换为json对象
            JSONObject jsonObject = JSONObject.parseObject(userObj);
            //创建一个方法，初始化微信对象，将原来的用户账号和微信对象进行绑定
            WxUser wxUser = initWxUser(jsonObject);
            //绑定
            System.out.println(user.getId());
            wxUser.setUser_id(user.getId());
            //调用mapper将数据添加到数据库
            wxUserMapper.add(wxUser);
            //记录对象loginInfo到redis中key值为token
            String token = UUID.randomUUID().toString();
            //设置对象在redis中保存的时间为30分钟有效
            redisTemplate.opsForValue().set(token, loginInfo, 30, TimeUnit.MINUTES);
            //如果登入成功需要返回 token和 对象 loginInfo
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("token", token);
            //对象传递到前端前，将隐蔽数据清空
            loginInfo.setSalt("");
            loginInfo.setPassword("");
            resultMap.put("loginInfo", loginInfo);
            return resultMap;
        }

        return null;
    }
    //根据微信查询的结果对象对象生成WxUser对象
    private WxUser initWxUser(JSONObject jsonObject) {
        //创建一个空的微信用户对象
        WxUser wxUser = new WxUser();
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setSex(jsonObject.getInteger("sex"));
        wxUser.setAddress(null);
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxUser.setUnionid(jsonObject.getString("unionid"));
        return wxUser;
    }
    //根据user对象生成LoginInfo对象
    private LoginInfo initLoginInfo(User user) {
        LoginInfo info = new LoginInfo();
        BeanUtils.copyProperties(user,info); //按照同名原则拷贝属性
        info.setType(1);
        return info;
    }
    //根据手机号生成user对象
    private User initUser(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        user.setEmail(null);
        //给一个随机密码
        String salt = UUID.randomUUID().toString();
        String password = MD5Utils.encrypByMd5(888888+salt);
        user.setPassword(password);
        user.setSalt(salt);
        user.setState(1);
        user.setDate(new Date());
        return user;
    }
   
}
